<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>

    <link rel="stylesheet" type="text/css" 
      href="/assets/css/straybirds.css" media="screen" />
    <link rel="stylesheet" type="text/css" 
      href="/assets/css/pygments.css" media="screen" />

    <!-- MathJax Section Start -->

    <script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    <script>
        MathJax.Hub.Config({
              tex2jax: {
              skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
              }
        });
        MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

    <!-- MathJax Section End -->

    <!-- Google Analytics Start-->
    <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-48100787-1', 'minixalpha.github.io');
  ga('send', 'pageview');

</script>

    <!-- Google Analytics End -->

    <title>web.py 源代码分析之 web.test 主要文件及测试流程</title>
  </head>

  <body>
    <div class="container">
      <header>
        <div class="container">
          <h1>
              <a href="/" title="Home Page"> 潇湘夜雨 </a>
          <span class="github-src">
            <a href ="https://github.com/minixalpha/minixalpha.github.io"
               target="_blank"
               title="Fork me on GitHub">
              <img src="/assets/images/GitHub-Mark-Light-32px.png" alt="">
            </a>
          </span>
          </h1>
        </div>
      </header>

      <aside id="left-side">
        <h2> 分类 </h2>
  <ul class="category-list">
      
            
                <li>
                <a href="/categories/计算机系统"> 计算机系统 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/java"> java (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/技术"> 技术 (5) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/工具"> 工具 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/科研"> 科研 (5) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/生活"> 生活 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/思想"> 思想 (2) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/c语言"> c语言 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/虚拟机"> 虚拟机 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/英语"> 英语 (8) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/读书"> 读书 (1) </a>
                </li>
            
      
            
                <li style="background-color: #444">
                <a href="/categories/源代码阅读"> 源代码阅读 (10) </a>
                </li>
            
      
  </ul>

      </aside>

      <aside id="right-side">
        <h2> 归档 </h2>
  <ul class="archive-list">
    
    
    
        
        
        
        
            
            <li>
                <a href="/2014/05">
                    2014-05 (1)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/04">
                    2014-04 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/03">
                    2014-03 (11)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/02">
                    2014-02 (6)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/01">
                    2014-01 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/11">
                    2013-11 (10)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/10">
                    2013-10 (3)
                </a>
            </li>

        
        
    
  </ul>

      </aside>

      <article>

<h1>目录文件说明</h1>

<h2>README</h2>

<p>如何运行测试文件，包含全部测试及分模块测试</p>

<p>调用</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/alltests.py
</code></pre></div>
<p>运行全部测试</p>

<p>调用</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/db.py
</code></pre></div>
<p>运行db模块测试</p>

<h2>alltest.py</h2>

<p>运行全部测试入口，调用 <code>webtest</code> 模块完成测试</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c"># alltest.py</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">webtest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span>
</code></pre></div>
<h2>webtest.py</h2>

<p>我们发现 webtest.py 中并没有 main 函数，而是从 <code>web.test</code> 中导入，</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c"># webtest.py</span>
<span class="kn">from</span> <span class="nn">web.test</span> <span class="kn">import</span> <span class="o">*</span>
</code></pre></div>
<p>也就是说，如果 <code>web.test</code>中有main函数的话，<code>webtest.main()</code>
其实是调用 <code>web.test</code> 中的main函数。</p>

<p>感觉～ 好神奇</p>

<h2>web.test</h2>

<p>看web目录下的test.py文件，果然发现了main函数，终于找到入口啦~</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">suite</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">suite</span><span class="p">:</span>
        <span class="n">main_module</span> <span class="o">=</span> <span class="nb">__import__</span><span class="p">(</span><span class="s">&#39;__main__&#39;</span><span class="p">)</span>
        <span class="c"># allow command line switches</span>
        <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">a</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;-&#39;</span><span class="p">)]</span>
        <span class="n">suite</span> <span class="o">=</span> <span class="n">module_suite</span><span class="p">(</span><span class="n">main_module</span><span class="p">,</span> <span class="n">args</span> <span class="ow">or</span> <span class="bp">None</span><span class="p">)</span>

    <span class="n">result</span> <span class="o">=</span> <span class="n">runTests</span><span class="p">(</span><span class="n">suite</span><span class="p">)</span>
    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">wasSuccessful</span><span class="p">())</span>
</code></pre></div>
<p>把这个main函数改掉，再运行一下：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/alltests.py
</code></pre></div>
<p>果然是运行修改后的函数，所以这里确定是入口。</p>

<p>在进入下一步之前，我们需要学习一下Python自动单元测试框架，即<code>unittest</code>模块。关于 <code>unittest</code> ，可以参考这篇文章：
<a href="http://www.ibm.com/developerworks/cn/linux/l-pyunit/">Python自动单元测试框架</a></p>

<p>现在，进入 <code>web.test.main</code>，
当我们如果我们打印 <code>main_module</code>，会得到</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&lt;module &#39;__main__&#39; from &#39;test/alltests.py&#39;&gt;
</code></pre></div>
<p>这说明调用时，<code>import</code> 得到的 <code>main</code> 与命令行调用指定的
调用的模块一致。</p>

<p>之后会调用 <code>module_suite</code> 得到需要测试的模块,</p>

<p>我们看一下 <code>module_suite</code> 的代码，</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">module_suite</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">classnames</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Makes a suite from a module.&quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="n">classnames</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestLoader</span><span class="p">()</span><span class="o">.</span><span class="n">loadTestsFromNames</span><span class="p">(</span><span class="n">classnames</span><span class="p">,</span> <span class="n">module</span><span class="p">)</span>
    <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="s">&#39;suite&#39;</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">module</span><span class="o">.</span><span class="n">suite</span><span class="p">()</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestLoader</span><span class="p">()</span><span class="o">.</span><span class="n">loadTestsFromModule</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
</code></pre></div>
<p>可以看出，module_suite分三部分，如果定义了 <code>classnames</code>，
会测试具体的类，否则，如果 <code>module</code> 中含有 <code>suite</code> 函数，
就返回此 <code>module.suite()</code> 的调用结果。</p>

<p>此时我们的 <code>module</code> 是之前得到的 </p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&lt;module &#39;__main__&#39; from &#39;test/alltests.py&#39;&gt;
</code></pre></div>
<p>而 <code>alltests.py</code> 中刚好就有 <code>suite</code> 函数：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">suite</span><span class="p">():</span>
    <span class="n">modules</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;doctests&quot;</span><span class="p">,</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;application&quot;</span><span class="p">,</span> <span class="s">&quot;session&quot;</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">webtest</span><span class="o">.</span><span class="n">suite</span><span class="p">(</span><span class="n">modules</span><span class="p">)</span>
</code></pre></div>
<p><code>modules</code> 是全部模块的列表，随后以此为参数，返回
调用 <code>webtest.suite</code> 的结果。</p>

<p>这时候，同样的情况又出现了，<code>webtest.py</code> 中没有 <code>suite</code> 函数，
但是 <code>webtest.py</code> 中含有</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="kn">from</span> <span class="nn">web.test</span> <span class="kn">import</span> <span class="o">*</span>
</code></pre></div>
<p>所以 <code>webtest.suite</code> 调用的还是 <code>web.test.suite</code>，</p>

<p>从这里我们可以看出，</p>

<blockquote>
<p>webtest.py 这个模块就是目录 <code>test</code> 下的模块与 <code>web.test</code> 模块
之间的一个过渡层，<code>test</code> 目录下的模块调用 <code>webtest.XXX</code>，而实际
的实现代码都是调用 <code>web.test.XXX</code>，所以，我们再次回到 <code>web.test</code>。</p>
</blockquote>

<p>看看 <code>web.test.suite</code>的实现：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">suite</span><span class="p">(</span><span class="n">module_names</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Creates a suite from multiple modules.&quot;&quot;&quot;</span>
    <span class="n">suite</span> <span class="o">=</span> <span class="n">TestSuite</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">mod</span> <span class="ow">in</span> <span class="n">load_modules</span><span class="p">(</span><span class="n">module_names</span><span class="p">):</span>
        <span class="n">suite</span><span class="o">.</span><span class="n">addTest</span><span class="p">(</span><span class="n">module_suite</span><span class="p">(</span><span class="n">mod</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">suite</span>
</code></pre></div>
<p>首先调用 <code>TestSuite()</code>，即 <code>unittest.TestSuite()</code>，得到一个
<code>suite</code>。然后，向 <code>suite</code> 中添加测试用例。</p>

<p>参数 <code>module_names</code> 就是刚刚的列表modules：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">modules = [&quot;doctests&quot;, &quot;db&quot;, &quot;application&quot;, &quot;session&quot;]
</code></pre></div>
<p>调用 <code>load_modules</code> 把模块名变为模块本身，
例如 &quot;application&quot;:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&gt;&gt;&gt; __import__(&quot;application&quot;, None, None, &quot;x&quot;)
&lt;module &#39;application&#39; from &#39;application.pyc&#39;&gt;
</code></pre></div>
<p>然后，再调用 <code>module_suite</code>，这时候你会发现，我们递归回来了，</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">module_suite</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">classnames</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Makes a suite from a module.&quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="n">classnames</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestLoader</span><span class="p">()</span><span class="o">.</span><span class="n">loadTestsFromNames</span><span class="p">(</span><span class="n">classnames</span><span class="p">,</span> <span class="n">module</span><span class="p">)</span>
    <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="s">&#39;suite&#39;</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">module</span><span class="o">.</span><span class="n">suite</span><span class="p">()</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestLoader</span><span class="p">()</span><span class="o">.</span><span class="n">loadTestsFromModule</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
</code></pre></div>
<p>此时, <code>module</code>为:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&lt;module &#39;application&#39; from &#39;application.pyc&#39;&gt;
</code></pre></div>
<p>我们再看看这时候，<code>application.py</code>中是否有 <code>suite</code>函数。
经过查看，发现没有，所以此时就会调用 <code>if</code>语句第三个分支：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">        <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestLoader</span><span class="p">()</span><span class="o">.</span><span class="n">loadTestsFromModule</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
</code></pre></div>
<p><a href="http://docs.python.org/2/library/unittest.html#unittest.TestLoader">TestLoader</a> 中的 <code>loadTestsFromModule</code> 从模块中导入
测试用例。 这个函数会搜索模块中 <code>TestCase</code>类的子类，再创建一个
子类的实例，以便调用子类中的测试函数。
例如 <code>test/application.py</code>中的 <code>ApplicationTest</code> 类：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">class</span> <span class="nc">ApplicationTest</span><span class="p">(</span><span class="n">webtest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_reloader</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">))</span>
        <span class="kn">import</span> <span class="nn">foo</span>
        <span class="n">app</span> <span class="o">=</span> <span class="n">foo</span><span class="o">.</span><span class="n">app</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">)</span>

        <span class="c"># test class change</span>
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;b&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;b&#39;</span><span class="p">)</span>

        <span class="c"># test urls change</span>
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;c&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;c&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;c&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">testUppercaseMethods</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">urls</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="s">&quot;hello&quot;</span><span class="p">)</span>
        <span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">locals</span><span class="p">())</span>
        <span class="k">class</span> <span class="nc">hello</span><span class="p">:</span>
            <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="s">&quot;hello&quot;</span>
            <span class="k">def</span> <span class="nf">internal</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="s">&quot;secret&quot;</span>

        <span class="n">response</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;internal&#39;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="s">&#39;405 Method Not Allowed&#39;</span><span class="p">)</span>

     <span class="o">...</span>
</code></pre></div>
<p>返回的这些函数会经过 <code>web.test.suite</code> 中的 <code>suite.addTest</code> 加入到
<code>suite</code>中。 这样经过循环，所有模块中的测试用例就加入 <code>suite</code>中。</p>

<p>之后，我们回到 <code>web.test.main</code> 中，调用</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="n">result</span> <span class="o">=</span> <span class="n">runTests</span><span class="p">(</span><span class="n">suite</span><span class="p">)</span>
</code></pre></div>
<p>完成最终的测试。 <code>runTests</code> 在 <code>web.test</code>模块中：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">runTests</span><span class="p">(</span><span class="n">suite</span><span class="p">):</span>
    <span class="n">runner</span> <span class="o">=</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TextTestRunner</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">runner</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">suite</span><span class="p">)</span>
</code></pre></div>
<p><code>runner</code>功能同样由 <code>unittest</code>模块提供。</p>

<p>到这里，我们应该明白了测试的整个过程的全部细节。</p>

<p>这里，我们对 <code>alltests.py</code> 完成的功能做一个总结。
从总体上看，<code>alltests.py</code>对所有模块完成测试,包括：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">    modules = [&quot;doctests&quot;, &quot;db&quot;, &quot;application&quot;, &quot;session&quot;]
</code></pre></div>
<p>我们绕来绕去，其实不过下列过程：</p>

<ul>
<li>通过 <code>suite=TestSuite()</code> 得到 <code>suite</code></li>
<li>把所有模块中的 test 函数  通过 <code>suite.addTest()</code> 加入 <code>suite</code></li>
<li>通过 <code>runner=unittest.TextTestRunner()</code> 得到 <code>runner</code></li>
<li>运行 <code>runner.run(suite)</code> 调用所有测试用例。</li>
</ul>

<p>之所以感觉绕，是因为 层次关系，及<code>alltests.py</code> 需要递归调用 <code>module_suite</code>:</p>

<ul>
<li><code>alltests.py</code> 调用 <code>webtest.main</code></li>
<li><code>webtest.main</code> 指向 <code>web.test.main</code> </li>
<li>由<code>web.test.main</code> 进入 <code>web.test.module_suite</code>，进入 <code>if</code> 第二分支</li>
<li>再进入 <code>alltest.py</code>，调用 <code>suite()</code></li>
<li>再进入 <code>web.test.suite</code> , 对每个模块调用 <code>web.test.module_suite</code></li>
<li>再进入 <code>web.test.module_suite</code>，进入 <code>if</code> 第三分支,得到每个模块中的 测试用例</li>
<li>将所有测试用例加入 <code>suite()</code> 中的 <code>suite</code></li>
</ul>

<h2>requirements.txt</h2>

<p>requirements.txt 文件可由 pip 生成：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$pip freeze -l &gt; requirements.txt
</code></pre></div>
<p>同时，pip 可以使用 requirements.txt 文件安装依赖包</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$pip install -r requirements.txt
</code></pre></div>
<p>这就为打包与安装包提供了方便</p>


      </article>

      <div class="comments">
        
          <div id="disqus_thread"></div>
 <script type="text/javascript">
     /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
     var disqus_shortname = 'minixalpha'; // required: replace example with your forum shortname

     /* * * DON'T EDIT BELOW THIS LINE * * */
     (function() {
         var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
         dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
         (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
     })();
 </script>
 <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
    

        
      </div>


      <footer>
        Copyright (c) minixalpha 2014
      </footer>

    </div>
  </body>
</html>
